#include "ServerSocket.h"
char SECRETKEY[32] = "88888888";	//注册VIP密钥

/*
 * 功能：初始化服务器网络配置
 * 形参：无
 * 返回值：服务器套接字
 */
int InitNet()
{
	int sockfd, ret;
	//创建
	sockfd = socket(PF_INET, SOCK_STREAM, 0);	
	
	if(sockfd == -1)
	{
		perror("socket");
        	return 1;
	}
	
	//绑定
	struct sockaddr_in server_addr;
	server_addr.sin_family = PF_INET;
	server_addr.sin_port = htons(9999);
	server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	ret = bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
	if(ret == -1)
	{
		perror("bind");
		return 1;
	}

	//监听
	ret = listen(sockfd, 10); //10为监听队列长度
	if(ret == -1)
	{
		perror("listen");
		return 1;
	}
	
	return sockfd;
}

/*
 * 功能：获得系统时间：年、月、日、时、分、秒
 * 形参：字符串地址(输出参数)
 * 返回值：无
 * 头文件：<time.h>
 */
void GetTime(char *str_time)
{
	int arr_time[6];
	time_t t;
    	struct tm * lt;
	time (&t);		//获取Unix时间戳
	lt = localtime (&t);	//转为时间结构
	
	arr_time[0] = lt->tm_year + 1900;
    	arr_time[1] = lt->tm_mon;
    	arr_time[2] = lt->tm_mday;
    	arr_time[3] = lt->tm_hour;
    	arr_time[4] = lt->tm_min;
    	arr_time[5] = lt->tm_sec;
	sprintf(str_time, "%d/%d/%d %d:%d:%d ",arr_time[0], arr_time[1], arr_time[2], arr_time[3], arr_time[4], arr_time[5]);
}

void MainHandler(int sockfd, Online *head)
{
	struct head_fd_struct head_fd;
	struct sockaddr_in client_addr;
	int lenth = sizeof(client_addr);
	int ret = 0; 
	int sock_conn = 0;
	while(1)
	{
		printf("等待客户端连接...\n");
		sock_conn = accept(sockfd, (struct sockaddr *)&client_addr,(socklen_t *)&lenth); //调用accept函数时，如果没有任何客户端连接请求到来，该函数会阻塞调用线程直到成功接收到一个客户端连接请求或出现错误才返回
		if (-1 == sock_conn)
		{
			perror("accept");
		}

		sleep(1);
		printf("客户端%d已经连接...\n", sock_conn);
		
		head_fd.head_s = head;
		head_fd.sock_conn = sock_conn;

		pthread_t tid;
		ret = pthread_create(&tid, NULL, RecvHandler, (void*)&head_fd);	//客户端连接，创建线程
		if(ret == -1)
		{
			perror("pthread_create");
			exit(1);
		}
	}
}

void *RecvHandler(void* data)
{
	struct head_fd_struct *head_fd = (struct head_fd_struct*)data;
	Chat c_recv;
	int fd, ret;
	Online *head;

	fd = head_fd->sock_conn;
	head = head_fd->head_s;
	Online *Node_tmp = (Online *)malloc(sizeof(Online));
	
	pthread_detach(pthread_self());
	while(1)
	{
		ret = recv(fd, &c_recv, sizeof(c_recv), 0);
		if(ret == -1)
		{
			perror("recvhandler recv");
			exit(1);
		}
		Node_tmp->fd = head_fd->sock_conn;
		strcpy(Node_tmp->id, c_recv.id);

		switch(c_recv.cmd)
		{
			case CMD_REGISTER:
				printf("1111111111111111111111111");
				register_handler(&c_recv, Node_tmp);	//注册
				printf("222222222222222222222222");
				break;	
			case CMD_LOGIN:
				login_handler(&c_recv, Node_tmp, head);	//登录
				break;
			case CMD_ONLINEUSER:
				printf("fsdhkjfhksdk");
				onlineuser_handler(&c_recv, fd, head);	//查看在线用户
				break;
			case CMD_PRIVATE:
				private_handler(fd, &c_recv, head);	//私聊
				break;	
			case CMD_GROUP:
				group_handler(fd, &c_recv, head);	//群发
				break;
			case CMD_FORBID:
				forbid_user_handler(fd, &c_recv, head);	//禁言
				break;
			case CMD_KICKOUT:
				kick_out_user_handler(fd, &c_recv, head);//踢人
				break;
			case CMD_OFFLINE:
				userexit(fd, &c_recv, head);		//下线
				break;
			case CMD_REGISTERVIP:
				register_vip(fd, &c_recv, head);	//注册会员
				break;
			case CMD_FILE:
				file_transfer(fd, &c_recv, head);	//传输文件
				break;
			case CMD_GETCHATINFO:
				get_database_chatinfo(fd, c_recv.id);	//聊天信息
				break;
			case CMD_EXIT:
				//客户端退出
				main_exit(head_fd->sock_conn, &c_recv, head_fd->head_s, Node_tmp);
				break;
			default:
				break;
		}
		memset(&c_recv, 0, sizeof(c_recv));
	}

	close(fd);
	return;
}

/*
 * 功能：注册处理函数
 * 形参：1、聊天信息结构体地址 2、新建在线信息结点地址
 * 返回值：无
 */
void register_handler(Chat *c, Online *Node_tmp)
{
	printf("5555555555555555");
	int ret;
	//初始化结点信息
	strcpy(Node_tmp->id, c->id);
	Node_tmp->forbid_flag = 0;
	Node_tmp->admin_flag = 0;

	ret = if_user_exist(c->id);
	if(ret == 1)
	{
		c->result = RES_USEREXIST;
		ret = send(Node_tmp->fd, c, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("send");
			exit(1);
		}
	}
	else
	{
		ret = write_database_userinfo(c);
		if (-1 == ret)
		{
			printf("write database failure!\n");
		}
	
		c->result = RES_SUCCESS;
		ret = send(Node_tmp->fd, c, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("send");
			exit(1);
		}
	}
}

/*
 * 功能：客户端登录处理函数
 * 形参：1、聊天信息结构体地址 2、新建在线信息结点地址 3、链表头结点地址
 * 返回值：无
 */
void login_handler(Chat *c, Online *Node_tmp, Online *head)
{
	int ret;
	Chat c_tmp;
	Online *Node, *Node_ID;
	
	//初始化结点信息
	strcpy(Node_tmp->id, c->id);
	Node_tmp->forbid_flag = 0;
	Node_tmp->admin_flag = 0;

	ret = if_user_exist(c->id);
	if(ret != 1)
	{
		c_tmp.result = RES_USERNOTEXIST;
		ret = send(Node_tmp->fd, &c_tmp, sizeof(c_tmp), 0);
		if (-1 == ret)
		{
			perror("login_handler send");
			exit(1);
		}		
	}
	else
	{
		Node_ID = GetNodeFromID(head,c->id);
		if (Node_ID != NULL && Node_ID->status == 1)
		{
			c_tmp.result = RES_USERONLINE;	

			ret = send(Node_tmp->fd, &c_tmp, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("login_handler_send1");
				exit(1);
			}
			return;
		}

		ret = if_passwd_exist(c->id, c->password);	//判断密码
		if(ret == 1)
		{
			printf("用户：%s 登陆成功！\n", c->id);
			//判断数据库是否为管理员
			if(if_user_admin(c->id) == 1)
			{
				c_tmp.admin_flag = 1;
			}
			else
			{
				c_tmp.admin_flag = 0;
			}

			Node = (Online*)malloc(sizeof(Online));
			memcpy(Node, Node_tmp, sizeof(Online));
			Node->status = 1;			//状态在线
			Node->admin_flag = c_tmp.admin_flag;	//管理员标志位
			Node->forbid_flag = 0;			//禁言标志位

			ret = InsertLink(head, 1, Node);	//登陆成功将用户节点信息插入链表
			if (0 == ret)
			{
				printf("插入链表失败\n");
			}

			c_tmp.result = RES_SUCCESS;
		
			ret = send(Node_tmp->fd, &c_tmp, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("login_handler_send2");
				exit(1);
			}
		}
		else
		{
			c_tmp.result = RES_PASSWDERROR;

			ret = send(Node_tmp->fd, &c_tmp, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("login_handler send3");
				exit(1);
			}
		}		
	}
}

/*
 * 功能：获得在线用户ID
 * 形参：1、接收到的Chat结构体地址 2、文件描述符套接字 3、在线用户信息链表头结点地址
 * 返回值：无
 */ 
void onlineuser_handler(Chat *c_recv, int fd, Online *head)
{
	printf("999999999999999999999999999999");
	Chat c_send;
	int ret;
	
	Online *l = head;
	while(l->next != NULL)
	{
		l = l->next;
		c_send.result = RES_WAITINGONLINE;
		strcpy(c_send.id_to, l->id);
		ret = send(fd, &c_send, sizeof(c_send), 0);
		if (-1 == ret)
		{
			perror("onlineuser_handler_send1");
			exit(1);
		}
	}
	
	c_send.result = RES_SUCCESS;

	ret = send(fd, &c_send, sizeof(c_send), 0);
	if (-1 == ret)
	{
		perror("onlineuser_handler_send2");
		exit(1);
	}
}

/*
 * 功能：私信处理函数
 * 形参：1、文件描述符 2、接收到的消息结构体地址 3、链表头结点
 * 返回值：无
 */
void private_handler(int fd, Chat *c, Online *head)
{
	Online *Node;
	Node = GetNodeFromID(head, c->id_to);
	Chat c_send;
	int ret;
	char time[32] = {0};
	
	memcpy(&c_send, c, sizeof(Chat));
	
	if (Node == NULL)
	{
		c_send.result = RES_USEROFFLINE;

		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_from");
			exit(1);
		}
		return;
	}
	
	if(Node->status == 1)
	{
		//给目标用户发信息
		c_send.result = RES_MESSAGE;
		ret = send(Node->fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_to");
			exit(1);
		}
		
		memcpy(&c_send, c, sizeof(Chat));
		//存储消息
		GetTime(time);		
		write_database_ChatInfo(&c_send, time);
		
		//给用户发成功信息
		c_send.result = RES_SUCCESS;
		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_from");
			exit(1);
		}
	}
	else
	{
		c_send.result = RES_USEROFFLINE;

		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_from");
			exit(1);
		}
	}	
}

/*
 * 功能：群发处理函数
 * 形参：1、文件描述符 2、接收到的消息结构体地址 3、链表头结点
 * 返回值：无
 */
void group_handler(int fd, Chat *c, Online *head)
{
	Online *Node; //保存目标用户信息结点地址
	int ret;
	Chat c_send, c_tmp;
	char time[32] = {0};

	strcpy(c_tmp.id_to, "ALLUSER");
	Node = GetNodeFromID(head,c->id_to);
	if (Node == NULL)
	{
		c_send.result = RES_USEROFFLINE;

		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_from");
			exit(1);
		}
	}

	if(Node->status == 1)
	{
		c_send.result = RES_MESSAGE;
		//给目标目标用户发送
		ret = send(Node->fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_to");
			exit(1);
		}
		
		//消息存入数据库
		GetTime(time);		
		write_database_ChatInfo(&c_tmp, time);
		
		c_send.result = RES_SUCCESS;
		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_from");
			exit(1);
		}
	}
	else
	{
		c_send.result = RES_USEROFFLINE;

		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("private_handler_send_from");
			exit(1);
		}
	}
}

/*
 * 功能：禁言处理函数
 * 形参：1、文件描述符 2、接收到的消息结构体地址 3、链表头结点
 * 返回值：无
 */
void forbid_user_handler (int fd , Chat* c, Online* head)
{
	int ret;
	Online *Node;
	Chat c_send;

	memcpy(&c_send, c, sizeof(Chat));
	Node = GetNodeFromID(head,c->id_to);
	
	ret = if_user_exist(c->id_to);
	if(ret != 1)
	{
		c_send.result = RES_USERNOTEXIST;	
		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("forbid_user_handler_send1");
			exit(1);
		}	
	}
	else
	{
		if (NULL == Node || Node->status == 0)
		{
			c_send.result = RES_USEROFFLINE;
			ret = send(fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("forbid_user_handler_send2");
				exit(1);
			}
		}
		else if (Node->admin_flag == 1)
		{
			c_send.result = RES_VIPEXIST;	
			ret = send(fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("forbid_user_handler_send3");
				exit(1);
			}		
		}
		else
		{
			c_send.result = RES_FORBIDSUCCESS;
			sprintf(c_send.text, "您已被%s禁言！", c->id);
			Node->forbid_flag = 1;
			ret = send(Node->fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("forbid_user_handler_send4");
				exit(1);
			}

			c_send.result = RES_SUCCESS;
			ret = send(fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("forbid_user_handler_send5");
				exit(1);
			}
		}
	}
	
}

/*
 * 功能：踢出用户处理函数
 * 形参：1、文件描述符 2、接收到的消息结构体地址 3、链表头结点
 * 返回值：无
 */
void kick_out_user_handler(int fd, Chat *c, Online *head)
{
	int ret;
	Chat c_send;
	Online *Node;

	memcpy(&c_send, c, sizeof(Chat));
	Node = GetNodeFromID(head,c->id_to);
	
	ret = if_user_exist(c->id_to);
	if(ret != 1)
	{
		c_send.result = RES_USERNOTEXIST;	
		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("kick_out_user_handler_send1");
			exit(1);
		}
	}
	else
	{
		if(NULL == Node || Node->status == 0)
		{
			c_send.result = RES_USEROFFLINE;
			ret = send(fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("kick_out_user_handler_send2");
				exit(1);
			}
		}
		else if(Node->admin_flag == 1)
		{
			c_send.result = RES_VIPEXIST;	
			ret = send(fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("kick_out_user_handler_send3");
				exit(1);
			}
		}
		else
		{
			c_send.result = RES_KICKOUT;
			sprintf(c_send.text, "您已被%s踢下线！", c->id);

			ret = DeleteNodeFromID(head, c->id_to);
			if (-1 == ret)
			{
				printf("删除踢出结点失败！\n");
			}

			ret = send(Node->fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("kick_out_user_handler_send4");
				exit(1);
			}

			c_send.result = RES_SUCCESS;
			ret = send(fd, &c_send, sizeof(Chat), 0);
			if (-1 == ret)
			{
				perror("kick_out_user_handler_send5");
				exit(1);
			}	
		}
	}
}

void userexit(int fd, Chat *c, Online *head)
{
	Chat c_send;
	int ret;

	if (RES_ASKEXIT == c->result)
	{
		printf("用户:%s已下线！\n", c->id);

		ret = DeleteNodeFromID(head, c->id);
		if (-1 == ret)
		{
			printf("删除下线结点失败！\n");
		}

		c_send.result = RES_USEREXIT;
		

		ret = send(fd, &c_send, sizeof(c_send), 0);
		if (-1 == ret)
		{
			perror("userexit_send");
			exit(1);
		}
	}
}

/*
 * 功能：注册VIP处理函数
 * 形参：1、文件描述符 2、接收到的消息结构体地址 3、链表头结点
 * 返回值：无
 */
void register_vip(int fd, Chat *c, Online *head)
{
	Chat c_send;
	int ret;
	Online *Node;
	memcpy(&c_send, c, sizeof(Chat));

	Node = GetNodeFromID(head,c->id);
	if(Node->admin_flag == 1)
	{
		c_send.result = RES_VIPEXIST;
		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("register_vip_send3");
			exit(1);
		}
		return;
	}
	
	//确认激活码
	if (strcmp(SECRETKEY, c->text) == 0)
	{
		Node->admin_flag = 1;
		ret = write_database_admin_flag(Node);	//写入数据库
		if (-1 == ret)
		{
			printf("插入数据库失败！\n");
		}
		
		c_send.result = RES_SUCCESS;
		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("register_vip_send1");
			exit(1);
		}		
	}
	else
	{
		c_send.result = RES_NOTADMIN;
		ret = send(fd, &c_send, sizeof(Chat), 0);
		if (-1 == ret)
		{
			perror("register_vip_send2");
			exit(1);
		}
	}
}

void file_transfer(int fd, Chat *c, Online *head)
{
	if (NULL == head || NULL == c)
	{
		return;
	}
	int ret;
	Chat c_send;
	memcpy(&c_send, c, sizeof(Chat));
	Online *Node;
	Node = GetNodeFromID(head,c->id_to);


	ret = send(Node->fd, &c_send, sizeof(Chat), 0);
	if (-1 == ret)
	{
		perror("file_transfer_send1");
		exit(1);
	}
}

/*
 * 功能：客户端退出处理函数
 * 形参：1、文件描述符 2、接收到的消息结构体地址 3、链表头结点 4、需要释放的临时结点
 * 返回值：无
 */
void main_exit(int fd, Chat *c, Online *head, Online *Node_tmp)
{
	Chat c_send;
	int ret;

	memcpy(&c_send, c, sizeof(Chat));
	c_send.result = RES_EXIT;

	ret = send(fd, &c_send, sizeof(c_send), 0);

	if (-1 == ret)
	{
		perror("main_exit_send");
		exit(1);
	}

	printf("客户端%d已退出...\n", fd);
	free(Node_tmp);
	sleep(1);
	close(fd);
	fd = 0;
	pthread_exit(NULL);		
}

